package com.boarsoft.boar.file.biz;

import java.util.List;

import com.boarsoft.common.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import com.boarsoft.boar.app.AppBiz;
import com.boarsoft.boar.app.AppFileBiz;
import com.boarsoft.boar.app.AppInstFileBiz;
import com.boarsoft.boar.dir.DirBiz;
import com.boarsoft.boar.entity.AppFile;
import com.boarsoft.boar.entity.AppInfo;
import com.boarsoft.boar.entity.AppInst;
import com.boarsoft.boar.entity.AppInstFile;
import com.boarsoft.boar.entity.DirInfo;
import com.boarsoft.boar.entity.FileInfo;
import com.boarsoft.boar.entity.FileVersion;
import com.boarsoft.boar.entity.ServerInfo;
import com.boarsoft.boar.file.FileBiz;
import com.boarsoft.boar.file.FileVersionBiz;
import com.boarsoft.common.Util;
import com.boarsoft.common.dao.PagedResult;
import com.boarsoft.hibernate.biz.SimpleBizImpl;

public abstract class FileBizImpl extends SimpleBizImpl implements FileBiz {
	@Autowired
	protected AppFileBiz appFileBiz;
	@Autowired
	protected FileVersionBiz fileVersionBiz;
	@Autowired
	protected AppInstFileBiz appInstFileBiz;
	@Autowired
	protected DirBiz dirBiz;
	@Autowired
	protected AppBiz appBiz;

	protected Class<? extends FileInfo> fileInfoClazz;

	@Override
	@Transactional(readOnly = true)
	public PagedResult<FileInfo> list(String projId, String key, String orderBy, int pageNo, int pageSize) {
		StringBuilder sb = new StringBuilder();
		sb.append(" from ").append(fileInfoClazz.getName());
		sb.append(" where 1=1");
		if (Util.strIsNotEmpty(projId)) {
			// sb.append(" and projId='").append(projId).append("'");
			DirInfo projDir = (DirInfo) dao.get(DirInfo.class, projId);
			sb.append(" and projId in (select DISTINCT id from DirInfo  where id='").append(projId).append("' or (type=")
					.append(DirInfo.TYPE_PROJ).append(" and path like '").append(projDir.getPath()).append("/").append(projId)
					.append("%'))");
		}
		if (Util.strIsNotEmpty(key)) {
			sb.append("and (code like '%").append(key);
			sb.append("%' or name like '%").append(key);
			sb.append("%' or memo like '%").append(key);
			sb.append("%')");
		}
		String ql = sb.toString();
		int total = dao.getTotal("select count(id)".concat(ql));
		if (Util.strIsNotEmpty(orderBy)) {
			sb.append(" order by ").append(orderBy);
		} else {
			sb.append(" order by code");
		}
		List<FileInfo> lt = dao.list(sb.toString(), pageNo, pageSize);
		return new PagedResult<FileInfo>(total, lt, pageNo, pageSize);
	}

	/**
	 * 在树上某个应用下增加配置文件需操作两张表 1，向file_info插入配置文件基础数据 2，向app_file插入应用与配置文件的关联关系记录
	 */
	@Override
	@Transactional
	public void save(String appId, FileInfo o) {
		FileInfo f=find(appId,o.getCode());
		if(f!=null){
			o.setId(f.getId());
			f.setName(o.getName());
			f.setType(o.getType());
			f.setMemo(o.getMemo());
			f.setCharset(o.getCharset());
			f.setDeployPath(o.getDeployPath());
			dao.update(f);
		}else {
			dao.save(o);
		}
		// 在新增配置文件时要维护应用和配置文件的关联关系，但是业务sql和shell不会关联到某个具体的应用上
		if (Util.strIsEmpty(appId)) {
			return;
		}
		AppInfo a = appBiz.get(appId);
		o.setProjId(a.getProjId());
		AppFile af = new AppFile();
		af.setAppId(appId);
		af.setFileId(o.getId());
		af.setFile(o);
		appFileBiz.save(af);
	}

	/**
	 * 在树上某个应用下增加配置文件需操作两张表 1，向file_info插入配置文件基础数据 2，向app_file插入应用与配置文件的关联关系记录
	 */
	@Override
	@Transactional
	public void update(String appId, FileInfo o) {
		dao.merge(o);
	}

	@Override
	public void save(FileInfo o) {
		if (Util.strIsEmpty(o.getId())) {
			dao.save(o);
		} else {
			dao.merge(o);
		}
	}

	@Override
	@Transactional
	public void delete(String id) {
		StringBuilder sb = new StringBuilder();
		// 删除文件版本
		sb.setLength(0);
		sb.append("delete from ").append(FileVersion.class.getName())//
				.append(" where fileId='").append(id).append("'");
		// 删除与应用的关系
		sb.setLength(0);
		sb.append("delete from ").append(AppFile.class.getName())//
				.append(" where fileId='").append(id).append("'");
		dao.executeUpdate(sb.toString());
		// 删除与应用实例的关系
		sb.setLength(0);
		sb.append("delete from ").append(AppInstFile.class.getName())//
				.append(" where fileId='").append(id).append("'");
		dao.executeUpdate(sb.toString());
		// 删除文件自身
		dao.delete(fileInfoClazz, id);
	}

	@Override
	@Transactional(readOnly = true)
	public FileInfo get(String id) {
		return (FileInfo) dao.get(fileInfoClazz, id);
	}


	@Override
	@Transactional(readOnly = true)
	public FileInfo find(String appId,String code) {
		StringBuilder sb = new StringBuilder();
		sb.append(" and appId='").append(appId).append("'");
		sb.append(" and code='").append(code).append("'");
		int total = dao.getTotal(FileInfo.class, sb.toString());
		if(total>1){
			throw new RuntimeException("appId:"+appId+",code:"+code+"的数量超过1个,同一应用下同一文件名应保证唯一,请联系环境组检查");
		}
		return dao.find(FileInfo.class, sb.toString());
	}
	/**
	 * 此功能在目录树上不可用（文件信息是不挂在目录树上的） 将来可另作它用
	 * <p/>
	 * 拷贝文件： 1，拷贝file_info 2，拷贝app_file
	 */
	@Override
	@Transactional
	public String copy(String sourceId, String parentId, String newId) {
		FileInfo o = this.get(sourceId);
		FileInfo n = (FileInfo) this.transfer(o, fileInfoClazz);
		n.setId(null);
		DirInfo d = dirBiz.get(parentId);
		String projId = dirBiz.lookup(d, DirInfo.TYPE_PROJ);
		n.setProjId(projId);
		n.setCreateTime(Util.getStdfDateTime());
		n.setLastTime(Util.getStdfDateTime());
		dao.save(n);
		appFileBiz.copy(sourceId, n.getId(), newId); // 应用的id来自于前一步骤的dir_info表id
		return newId;
	}

	/**
	 * 查找出文件关联的服务器 注：文件没有直接和服务器关联 通过查询文件关联的应用，再查询应用关联的服务器实现
	 */
	@Override
	@Transactional(readOnly = true)
	public List<ServerInfo> findFilesOnServer(String fileId) {
		StringBuilder sb = new StringBuilder();
		sb.append("select s from ").append(ServerInfo.class.getName()).append(" s where s.id in (")
				.append("select ai.serverId from ").append(AppInst.class.getName()).append(" ai where ai.appId in (")
				.append("select af.appId from ").append(AppFile.class.getName()).append(" af where af.fileId='").append(fileId)
				.append("'))");
		List<ServerInfo> serverInfoList = dao.list(sb.toString());
		return serverInfoList;
	}
}